home *** CD-ROM | disk | FTP | other *** search
/ Network CD 2 / Network CD - Volume 2.iso / programs / internet / dnet / dshterm1_0.lha / client / dshterm.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-02-04  |  14.6 KB  |  511 lines

  1. /**********************************************************
  2.  *                                                        *
  3.  * Minimal Term for DNET (uc) Stone, SST                  *
  4.  * Further modifications by Unknown, SST                  *
  5.  * Based on FTerm by Matt Dillon                          *
  6.  
  7.    Opens a terminal inside a CLI (for use with WSHELL
  8.    or SPHINX)
  9.  
  10.  *                                                        *
  11.  * ShellTerm [DNET_PORT] [NETWORK]                        *
  12.  *                                                        *
  13.  * Set ya TABS to 4!                                      *
  14.  * Email me!! c9107253@mystra.newcastle.edu.au            *
  15.  * For any reason!! (eg DNet, AmiNet, Demos, amigas...)   *
  16.  * Please send any changes U make!                        *
  17.  * Fully public domain                                    *
  18.  * Mega-thanx to Azza of the SST for hours of DNET source *
  19.  * modification.... yes it compiles under SAS 6!          *
  20.  *                                                        *
  21.  
  22.    BUGS:
  23.    ­ the way the conwindow size is determined is not
  24.    fail safe... so programs such a vi only sometimes work
  25.    readjust the window smaller if this happens
  26.  
  27.    ­ toggling between raw and buffer modes may take up to
  28.    1/2 second this can be fixed if 2 file locks on the
  29.    input are used.
  30.  
  31.    ­ Any others?
  32.  
  33.  *                                                        *
  34.  **********************************************************/
  35.  
  36. #include "defs.h"
  37.  
  38. /* DEFAULT STRINGS */
  39. char    *WHITE        = " \n\r\t",
  40.         *EOLN        = "\n\r";
  41.  
  42. /* STANDARD FILE HANDLES */
  43. long    out, err, in;
  44.  
  45. /* WINDOW SIZE */
  46. short    columns = 0, rows = 0;
  47.  
  48. /* FILE HANDLES */
  49. struct    AFileHandle    *ain, *aout, *alogfile;
  50.  
  51. /* PROGRAM FLAGS */
  52. char    overridepkt, prevmoderaw, rawlocalecho, moderaw, notdone, gettingoptions,
  53.         checkwindowsize;
  54. long    lineend;
  55.  
  56. char    Buf[512], prg[40], logfilename[100];
  57. void    *chan;
  58. long    startmem;
  59.  
  60. /* Window pointer of the console window (if we are interactive) */
  61. struct    Window *conwdw;
  62. #define COLUMNS(a)        ((a)->GZZWidth / (((a)->IFont->tf_XSize>0) ? (a)->IFont->tf_XSize:1))
  63. #define ROWS(a)            ((a)->GZZHeight / (((a)->IFont->tf_YSize>0) ? (a)->IFont->tf_YSize:1))
  64.  
  65. extern struct IntuitionBase    *IntuitionBase;
  66. extern struct GfxBase        *GfxBase;
  67.  
  68.  
  69. #define SIGNALS (SIGBREAKF_CTRL_C | SIGBREAKF_CTRL_D | SIGBREAKF_CTRL_E | SIGBREAKF_CTRL_F)
  70.  
  71. /* standard in & out async file handles */
  72. #define INBUFSIZE        500
  73. #define WAIT_TIMEOUT    700000 /* uSeconds */
  74.  
  75.  
  76. /* Do this on the next packet return */
  77. #define IN_NULL            0
  78. #define IN_WAIT            1
  79. #define IN_CHARS        2
  80. #define IN_RAWSET        3
  81. #define IN_RAWCLR        4
  82.  
  83.  
  84. /**********************************************************/
  85. void  DoPacket(struct AFileHandle *afh, void *qbuf,
  86.                                     long size, char pkttype)
  87. /**********************************************************
  88.      Send a packet according to type. qbuf & size may not
  89.          be required (in fact only used for ARead)
  90.  **********************************************************/
  91. {
  92.     switch(pkttype) {
  93.         case IN_WAIT:
  94.             ASendPacket(afh, ACTION_WAIT_CHAR, WAIT_TIMEOUT, 0, 0, 0); break;
  95.         case IN_CHARS:
  96.             ARead(afh, qbuf, size); break;
  97.         case IN_RAWSET:
  98.             ASendPacket(afh, ACTION_SCREEN_MODE, 1, 0, 0, 0); break;
  99.         case IN_RAWCLR:
  100.             ASendPacket(afh, ACTION_SCREEN_MODE, 0, 0, 0, 0); break;
  101.     }
  102. }
  103.  
  104.  
  105.  
  106. /* pass: rest of argline, command table, command count*4 */
  107. typedef void *(* cmdfunc)(char *);
  108. /**********************************************************
  109.                   Commands available
  110.  **********************************************************/
  111.  
  112. /* NOTE!!! ARGUMENTS **MUST** FIT PROTOTYPE of cmdfunc!!!! */
  113.  
  114. void cmds_raw(void)
  115. { overridepkt = IN_RAWSET; }
  116. void cmds_buf(void)
  117. { overridepkt = IN_RAWCLR; }
  118. void cmds_lf(void)
  119. { lineend = 0x0a000000; }
  120. void cmds_cr(void)
  121. { lineend = 0x0d000000; }
  122. void cmds_lfcr(void)
  123. { lineend = 0x0a0d0000; }
  124. void cmds_send(char *rest)
  125. { long n; if(rest && (n = strlen(rest))) DWrite(chan, rest, n); }
  126. void cmds_flush(void)
  127. { DIoctl(chan, CIO_FLUSH, 0, 0); fpf(err,"\nFlushed\n"); }
  128. void cmds_closelog(void)
  129. {
  130.     if(!alogfile) return;
  131.     fpf(err,"'%s' ", logfilename);
  132.     ASafeClose(&alogfile);
  133.     fpf(err,"closed ok.\n");
  134. }
  135. void cmds_log(char *rest)
  136. {
  137.     cmds_closelog();
  138.     if(!rest) return;
  139.     spf(logfilename, sizeof(logfilename), rest, aout);
  140.     fpf(err,"'%s' ", logfilename);
  141.     if( !(alogfile = AEasyOpen(aout, rest, MODE_NEWFILE)) )
  142.         fpf(err,"failed.\n"); else fpf(err,"opened ok.\n");
  143. }
  144. void cmds_execute(char *rest)
  145. {
  146.     if(!rest) return;
  147.     fpf(err,"%s Executing '%s'\n", prg, rest);
  148.     Execute(rest, NULL, err);
  149.     fpf(err,"%s Terminating '%s'\n", prg, rest);
  150. }
  151. void cmds_localecho(void)
  152. { rawlocalecho = 1; }
  153.  
  154. void cmds_localechooff(void)
  155. { rawlocalecho = 0; }
  156.  
  157. void cmds_ctrlf(void)
  158. { char c = 6; DWrite(chan, &c, 1); }
  159.  
  160. void cmds_quit(void)
  161. { notdone = 0; }
  162.  
  163. void cmds_getoptions(void)
  164. {
  165.     fpf(err,"\n%s (%ld x %ld)  ? <return> for help\n", prg, columns, rows);
  166.     if(prevmoderaw = moderaw) overridepkt = IN_RAWCLR;
  167.     gettingoptions = 1;
  168.  
  169. }
  170. /** ADD ANY NEW COMMANDS HERE */
  171.  
  172.  
  173. #define NOOFCMDS    ((sizeof(cmds)/4)/4)
  174. void cmds_help(char *dummy);
  175. static char *cmds[] = {
  176.     "HELP","?","This message",                (char *)cmds_help,
  177.     "RAW","R","Raw (normal terminal) mode",    (char *)cmds_raw,
  178.     "BUF","B","Line buffered (shell) mode",    (char *)cmds_buf,
  179.     "LFCR",NULL,"Linefeed & Carriage Return",(char *)cmds_lfcr,
  180.     NULL,"LF","Linefeed",                    (char *)cmds_lf,
  181.     NULL,"CR","Carriage return",            (char *)cmds_cr,
  182.     "SEND",NULL,"Send text",                (char *)cmds_send,
  183.     "FLUSH","^F","Flush input",                (char *)cmds_flush,
  184.     "EXECUTE","X","AmigaDOS command",        (char *)cmds_execute,
  185.     "LOCALECHO","LE","Raw mode local echo on",(char *)cmds_localecho,
  186.     "LOCALECHOOFF","LEO","Raw mode local echo off",(char *)cmds_localechooff,
  187.     "LOG","L","Log to file",                (char *)cmds_log,
  188.     "CLOSELOG","CL","Close log file",        (char *)cmds_closelog,
  189.     NULL,"F","Send CTRL-F",                    (char *)cmds_ctrlf,
  190.     "QUIT", NULL, "Quit terminal",            (char *)cmds_quit
  191. };
  192.  
  193. void cmds_help(char *dummy)
  194. { short j, i;
  195.     fpf(err,"Known commands:\n");
  196.     for(j = 0, i = 0; i < NOOFCMDS; j += 4, i++ )
  197.         if(cmds[j+1] && cmds[j])
  198.             fpf(err, "%s\tor %s (%s)\n",cmds[j+1], cmds[j], cmds[j+2]);
  199.         else if(cmds[j+1])
  200.             fpf(err, "%s\t(%s)\n", cmds[j+1], cmds[j+2]);
  201.         else if(cmds[j])
  202.             fpf(err, "%s\t(%s)\n", cmds[j], cmds[j+2]);
  203. }
  204. /**********************************************************/
  205. void                *ParseCommand(char *cmd)
  206. /**********************************************************
  207.   Send this routine a command string and it will try and
  208.                do something with it!
  209.  **********************************************************/
  210. {
  211. char cmdbuf[400], *command, *rest;
  212. short n;
  213.  
  214. /** KICK BACK INTO RAW IF WE WERE BEFORE (THO THIS MAY CHANGE) */
  215.     overridepkt = prevmoderaw? IN_RAWSET : IN_NULL;
  216.  
  217. /** GET THE COMMAND */
  218.     CopyMem(cmd, cmdbuf, sizeof(cmdbuf)-1); cmdbuf[sizeof(cmdbuf)-1] = 0;
  219.     command = SkipChar(cmdbuf, WHITE);
  220.     if(!command) return(NULL);
  221.     if( rest = FindChar(command, WHITE)) {
  222.         char *temp = SkipChar(rest, WHITE);
  223.         rest[0] = '\0'; rest = temp;
  224.         if(rest) {
  225.             temp = FindChar(rest, EOLN);
  226.             if(temp) temp[0] = '\0';
  227.         }
  228.     }
  229.     strupper(command);
  230.  
  231. /** DETERMINE THE COMMAND & DO THE CALL! */
  232.     if((n = CmpString(command, cmds, NOOFCMDS, 4)) == -1 )
  233.         if((n = CmpString(command, &cmds[1], NOOFCMDS, 4)) == -1 )
  234.             { fpf(err, "%s unrecognised\n", command); return(NULL); }
  235. /*    fpf(err, "%s corresponds to %ld\n", command, n); */
  236.     return(((cmdfunc)cmds[(n<<2)+3])(rest));
  237. }
  238.  
  239.  
  240.  
  241.  
  242. typedef  short (* mapfunc)(void *, char);
  243. /**********************************************************/
  244. long MapText(mapfunc fn, void *fn_data,
  245.                         unsigned char buffer[], short n)
  246. /**********************************************************
  247.   Bit of a mess... just map some characters to others...
  248.  **********************************************************/
  249. {
  250. short i,j;
  251. long w;
  252. char *eoln;
  253.     eoln = (char *)&lineend;
  254.     for(w = 0, i = 0; i < n; i++) {
  255.         switch(buffer[i]) {
  256.             case 0x03:    /** CTRL-C */
  257.             case 0x04:    /** CTRL-D */
  258.             case 0x05:    /** CTRL-E */
  259.             case 0x06:    /** CTRL-F */
  260.                 break;
  261.  
  262.             case 0x0a:
  263.             case 0x0d:    /** RETURN */
  264.                 for(j = 0; eoln[j]; j++)
  265.                     if(!fn(fn_data, eoln[j])) return(w); else w++;
  266.                 break;
  267.             case 0x9b:    /** ARROW KEY ESCAPE */
  268.                 if(!fn(fn_data, 0x1b)) return(w); else w++;
  269.                 if(!fn(fn_data, '[')) return(w); else w++;
  270.                 break;
  271.  
  272.             default:    /** PUT THROUGH */
  273.                 if(!fn(fn_data, buffer[i])) return(w); else w++;
  274.         }
  275.     }
  276.     return(w);
  277. }
  278.  
  279. struct InterData { void *channel; short position; char buffer[256]; };
  280.  
  281. short DNet_DoWrite(struct InterData *data, char c)
  282. {    data->buffer[data->position++] = c;
  283.     if(data->position >= 256)
  284.         { DWrite(data->channel, data->buffer, data->position); data->position = 0; }
  285.     return(1);
  286. }
  287.  
  288. void WriteText(void *dchan, char *buffer, short n)
  289. {
  290. struct InterData data;
  291.     data.position = 0; data.channel = dchan;
  292.     if(rawlocalecho && moderaw)
  293.         { AWrite(aout, buffer, n); if(alogfile) AWrite(alogfile, buffer, n); }
  294.     MapText(DNet_DoWrite, &data, (unsigned char *)buffer, n);
  295.     if(data.position) DWrite(data.channel, data.buffer, data.position);
  296. }
  297.  
  298.  
  299.  
  300. /**********************************************************/
  301.            long main(int argc, char **argv)
  302. /**********************************************************
  303.                 Do the minimal term stuff!
  304.         Wait on our message ports for incoming
  305.  **********************************************************/
  306. {
  307. long    amask, dmask, mask;
  308. char    *hostname = NULL,
  309.         inbuf[INBUFSIZE],
  310.         currpkt, scriptmode;
  311.  
  312. UWORD    port    =    PORT_IALPHATERM;
  313. struct    Process *us;
  314.     startmem = AvailMem(MEMF_PUBLIC);
  315.  
  316. /** STUFF WE NEED */
  317.     out = Output(); in = Input(); err = Open("*", MODE_OLDFILE);
  318.     us = (struct Process *)FindTask(NULL); SetSignal(0,SIGNALS);
  319.     spf(prg, sizeof(prg), "%s [%s %ld]", argv[0], us->pr_Task.tc_Node.ln_Name, us->pr_TaskNum);
  320.     IntuitionBase = (struct IntuitionBase *)OpenLibrary("intuition.library", 0);
  321.     GfxBase = (struct GfxBase *)OpenLibrary("graphics.library", 0);
  322.  
  323.  
  324. /** PRINT USAGE */
  325.     fpf(out,"ShellTerm for DNET (uc) Stone, SST\n"
  326.         "email: c9107253@mystra.newcastle.edu.au or c9107253@cs.newcastle.edu.au\n"
  327.         "\nCTRL-\\ or CTRL-F then CTRL-C to quit, CTRL-F for options\n\n");
  328.     if( argc<2 )
  329.         fpf(err,"(Use: %s [>file] [<file] [DNET_PORTNUMBER] [NETWORK])\n", argv[0]);
  330.  
  331.  
  332. /** PARSE COMMAND LINE */
  333.     if(argc > 1) port = (UWORD) atoi(argv[1]);
  334.     if(argc > 2) hostname = argv[2];
  335.  
  336.  
  337. /** GET ASYNC INPUT & OUTPUT HANDLES ON DIFFERENT PORTS */
  338.     if(! (ain = AEasyMakeFD2AFD(NULL, in)))
  339.         { fpf(err, "No input!?\n"); goto e3; }
  340.     if(! (aout = AEasyMakeFD2AFD(NULL, out)))
  341.         { fpf(err, "No output!?\n"); goto e3; }
  342.     if(!IsInteractive(((long)(ain->FileHandle))>>2))
  343.         { fpf(err, "Warning: input is not of console type\n"); conwdw = NULL; }
  344.  
  345.  
  346. /** FIND WINDOW OF THIS CONSOLE PROCESS */
  347.     if(IsInteractive(((long)(aout->FileHandle))>>2)) {
  348.         struct InfoData *info;
  349.         if(!(info = (struct InfoData *)
  350.             AllocMem(sizeof(struct InfoData), MEMF_CHIP | MEMF_CLEAR)) )
  351.         { fpf(err, "No memory left!\n"); goto e3; }
  352.         ASendPacket(aout, ACTION_DISK_INFO, ((long)info)>>2, 0, 0, 0);
  353.         AResultWait(aout);
  354.         conwdw = (struct Window *)info->id_VolumeNode;
  355.         fpf(err, "window=%08lx COLS=%ld, ROWS=%ld\n",conwdw,
  356.                         COLUMNS(conwdw), ROWS(conwdw));
  357.         if(((long)conwdw)&1) conwdw = NULL;
  358.         FreeMem(info, sizeof(struct InfoData));
  359.     } else fpf(err,"WARNING: output is not interactive\n");
  360.     checkwindowsize = conwdw? 1:0;
  361.  
  362.  
  363. /** INITIALIZE STUFF */
  364.     DoPacket(ain, 0, 0, currpkt = IN_WAIT);
  365.     overridepkt = IN_NULL;
  366.     cmds_lf();
  367.     cmds_localechooff();
  368.     moderaw = 0; gettingoptions = 0; 
  369.  
  370.  
  371. /** DO THAT FUNKY DNET STUFF */
  372.     fpf(out,"Opening port %ld on network %s ",port,hostname?hostname:"0");
  373.     if( ! (chan = DOpen(hostname, port, 20, 15)) )
  374.         { fpf(err,"Sorry, Unable to connect\n"); goto e3; }
  375.     DQueue(chan, 32);
  376. /*    DIoctl(chan, CIO_SETROWS, 25, 0); DIoctl(chan, CIO_SETCOLS, 80, 0); */
  377.     fpf(out,"connected\n");
  378.  
  379.  
  380. /** KEEP ON LOOPING */
  381.     dmask   = 1 << ((PORT *)chan)->mp_SigBit;
  382.     amask    = 1 << ASIGBIT(ain);
  383.     for (notdone = 1; notdone;) {
  384.  
  385.     /** CHECK THE WINDOW SIZE */
  386.         if(conwdw && checkwindowsize) {
  387.             if(columns != COLUMNS(conwdw))
  388.                 DIoctl(chan, CIO_SETCOLS, columns = COLUMNS(conwdw), 0);
  389.             if(rows != ROWS(conwdw))
  390.                 DIoctl(chan, CIO_SETROWS, rows = ROWS(conwdw), 0);
  391.         }
  392.  
  393.         mask = Wait(amask | dmask | SIGNALS);
  394.  
  395.     /** CHECK ASYNC INPUT FROM USER */
  396.         if (mask & amask) {
  397.             long n; struct AFileHandle *currafh;
  398.  
  399.         /** BE *VERY* CAREFUL ON WHERE WE MAY "ACCIDENTALLY" GETMSG */
  400.             while(currafh = AGetReply(ain->APort)) {
  401.                 n = AResult(currafh);
  402.                 if(currafh == ain) {
  403.                 /** CHECK REPLY OF PACKET */
  404.                     switch(currpkt) {
  405.                         case IN_WAIT:
  406.                             currpkt = n? IN_CHARS: IN_WAIT;
  407.                             break;
  408.                         case IN_CHARS:
  409.                             currpkt = IN_WAIT;
  410.                             if(!n) notdone = 0;
  411.                             else if(n > 0) {
  412.                                 if(gettingoptions && !moderaw) {
  413.                                     inbuf[n] = '\0';
  414.                                     ParseCommand(inbuf);
  415.                                     gettingoptions = 0;
  416.                                 } else
  417.                                     WriteText(chan, inbuf, n);
  418.                             }
  419.                             break;
  420.                         case IN_RAWSET:
  421.                             currpkt = IN_WAIT;
  422.                             if(!n) fpf(err, "Couldn't set terminal mode RAW\n");
  423.                             else moderaw = 1;
  424.                             break;
  425.                         case IN_RAWCLR:
  426.                             currpkt = IN_WAIT;
  427.                             moderaw = 0;
  428.                             break;
  429.                     }
  430.                 /** SEND OUT NEXT PACKET (NOW CURRENT PACKET) */
  431.                     if(overridepkt) currpkt = overridepkt;  overridepkt = 0;
  432.                     DoPacket(currafh, inbuf, sizeof(inbuf)-4, currpkt);
  433.  
  434.                 } /* else OTHER INPUT FILES (others?? nah!) */
  435.             }
  436.         }
  437.  
  438.  
  439.     /** CHECK SIGNALS (AND SEND THEM PERHAPS) */
  440.         if(mask & SIGBREAKF_CTRL_C) {
  441.             if(gettingoptions) cmds_quit();
  442.             else { char c = 3; DWrite(chan, &c, 1); }
  443.         }
  444.  
  445.         if(mask & SIGBREAKF_CTRL_D)
  446.             { char c = 4; DWrite(chan, &c, 1); }
  447.  
  448.         if(mask & SIGBREAKF_CTRL_E)
  449.             { char c = 5; DWrite(chan, &c, 1); }
  450.  
  451.         if(mask & SIGBREAKF_CTRL_F) {
  452.             if(gettingoptions) {
  453.                 cmds_flush();
  454.                 gettingoptions = 0;
  455.             } else cmds_getoptions();
  456.         }
  457.  
  458.  
  459.     /** CHECK DNET */
  460.         if (mask & dmask) {
  461.             long n;
  462.             if ((n = DNRead(chan, Buf, sizeof(Buf))) > 0) {
  463.                 /* WE GOT SOME TEXT! PRINT TO STD OUTPUT! */
  464.                 AWrite(aout, Buf, n);
  465.                 if(alogfile) AWrite(alogfile, Buf, n);
  466.             } else if (n == -2) {
  467.                 short val, cmd; char aux;
  468.                 cmd = DGetIoctl(chan, &val, &aux);
  469.                 switch(cmd) {
  470.                     case CIO_MODE:
  471.                         overridepkt = val ? IN_RAWCLR: IN_RAWSET; break;
  472.                     case CIO_SETROWS:
  473.                         break;
  474.                     case CIO_SETCOLS:
  475.                         break;
  476.                 }
  477.  
  478.             } else if (n < 0) cmds_quit();
  479.         }
  480.  
  481.     }
  482.  
  483.  
  484. /** END ALL THE PAIN */
  485. e3:
  486.     if(ain && moderaw) {
  487.         fpf(err,"\nChanging mode back to normal");
  488.         AResultWait(ain);
  489.         DoPacket(ain, 0, 0, IN_RAWCLR); }
  490.  
  491.     fpf(err,"\n%s Closing channel. ", prg);
  492.     if(chan) DClose(chan);
  493. /** CLOSE ALL FILES ON THE 2 PORTS */
  494.     fpf(err,"output. ");
  495.     ADeletePort(aout->APort);
  496.     fpf(err,"input. ");
  497.     ADeletePort(ain->APort);
  498.     fpf(err,"done!\n");
  499.     if(err) Close(err);
  500.     CloseLibrary((LIB *)IntuitionBase);
  501.     CloseLibrary((LIB *)GfxBase);
  502.     return(0);
  503. }
  504.  
  505. /* to add:
  506.  
  507. arexx support
  508. text message support
  509.  
  510. */
  511.